import cv2
import pyautogui        #换成ctypes库调用 Windows 的 API 函数实现底层操纵不触及鼠标事件
import random
import time
import log_proc as log
import os
from constants import *
import numpy as np


class BasicOperations:
    def __init__(self):
        self.saveDir = save_directory

    def removeTempShotList(self):
        directory = self.saveDir
        # 检查指定目录是否存在
        if not os.path.exists(directory):
            print(f"指定的目录 {directory} 不存在。")
            return
        # 遍历指定目录下的所有文件和文件夹
        for root, dirs, files in os.walk(directory):
            for file in files:
                # 检查文件扩展名是否为 .jpg
                if file.lower().endswith('.jpg'):
                    file_path = os.path.join(root, file)
                    try:
                        # 删除文件
                        os.remove(file_path)
                        # print(f"已删除文件: {file_path}")
                    except Exception as e:
                        print(f"删除文件 {file_path} 时出错: {e}")

    # 相关性匹配法,判断 maxVal 是否大于某个阈值来确定是否匹配
    def tm_co_diff(self, maxVal):
        # 设定阈值
        threshold = 0.8

        # 判断是否匹配
        if maxVal >= threshold:
            return True
        else:
            return False
    # 像素匹配算法
    def pixel_match(self, img1, img2, tolerance=100):
        if img1.shape != img2.shape:
            return False
        diff = np.abs(img1.astype(np.int32) - img2.astype(np.int32))
        return np.all(diff <= tolerance)
    # 调用像素匹配的图像识别，仅用在王点检测
    def compare_images_pixel(self, template_path, target_path, top_left, bottom_right):  # top=max, bot = min
        # 读取图片
        target = cv2.imread(target_path, cv2.IMREAD_COLOR)
        template_path = cv2.imread(template_path, cv2.IMREAD_COLOR)

        # 根据左上角和右下角坐标划定区域
        x1, y1 = top_left
        x2, y2 = bottom_right
        roi = target[y1:y2, x1:x2]
        if not self.pixel_match(roi, template_path):
            # print("像素差值不一致")
            return False
        # cv2.imshow('target', roi)
        # cv2.imshow('template', template_path)
        # cv2.waitKey(0)
        # cv2.destroyAllWindows()
        return True

    # 调用模板匹配，读取模板图像和目标图像并匹配，返回匹配顶点坐标
    def find_template_in_image(self, template_path, target_path):
        # 读取模板图像和目标图像
        template = cv2.imread(template_path, cv2.IMREAD_COLOR)
        target = cv2.imread(target_path, cv2.IMREAD_COLOR)

        if template is None or target is None:
            raise FileNotFoundError("无法读取图片，请检查文件路径。")

        # 获取模板图像的宽度和高度
        h, w, _ = template.shape

        # 使用模板匹配方法，这里使用TM_CCOEFF_NORMED方法
        result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)

        # 获取匹配结果中的最小值、最大值以及它们的位置
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

        if self.tm_co_diff(max_val):
            bottom_right = (max_loc[0] + w, max_loc[1] + h)
            # # 在目标图像上绘制矩形框标记出匹配区域
            # cv2.rectangle(target, max_loc, bottom_right, (0, 255, 0), 2)
            # cv2.imshow('Matched Image', target)
            # cv2.waitKey(0)
            # cv2.destroyAllWindows()
            return (max_loc, bottom_right)  # 返回矩形icon在输入图片内的对角坐标
        else:
            return ([], [])

    # 输入屏幕坐标，移动鼠标到该位置并执行action操作
    def control_mouse(self, x, y, action='move'):
        # print("move to (" + str(x) + "," + str(y) + "), action=" + action)
        # 移动鼠标到指定坐标
        if action == 'move':
            pyautogui.moveTo(x, y)
        # 左键单击
        elif action == 'left_click':
            pyautogui.click(x, y, button='left')
        # 右键单击
        elif action == 'right_click':
            pyautogui.click(x, y, button='right')
        # 双击左键
        elif action == 'double_left_click':
            pyautogui.doubleClick(x, y, button='left')
        # 按住左键拖动
        elif action == 'drag':
            pyautogui.dragTo(x, y, button='left')
        else:
            log.info('不支持的鼠标操作')

    # 根据顶点坐标计算随机点击坐标，点击后等待IntervalClick秒再返回
    def inputLocationAndClick(self, maxLoc, bottomRight):
        # log.info("开始计算坐标并点击…")
        bottomLine = 10  # 这个范围应当取决于手指习惯接触，游戏判定范围,和输入截图相对于原图大小
        if bottomRight[0] - maxLoc[0] > 2 * bottomLine:
            coordinateX = random.randint(maxLoc[0] + bottomLine, bottomRight[0] - bottomLine)
        else:
            coordinateX = random.randint(maxLoc[0], bottomRight[0])
        if bottomRight[1] - maxLoc[1] > 2 * bottomLine:
            coordinateY = random.randint(maxLoc[1] + bottomLine, bottomRight[1] - bottomLine)
        else:
            coordinateY = random.randint(maxLoc[1], bottomRight[1])
        self.control_mouse(coordinateX, coordinateY, action='left_click')
        time.sleep(IntervalClick)

    # 截取一张当前屏幕图片并保存到save_directory目录下，返回文件路径
    def autoScreemShot(self):
        # 如果目录不存在，则创建目录
        self.saveDir = save_directory
        if not os.path.exists(self.saveDir):
            os.makedirs(self.saveDir)

        try:
            # 获取当前时间戳，用于生成唯一的文件名
            timestamp = int(time.time())
            # 生成文件名
            filename = os.path.join(save_directory, f'screenshot_{timestamp}.jpg')

            # 进行屏幕截图
            screenshot = pyautogui.screenshot()

            # 保存截图为JPG格式
            screenshot.save(filename)
            # print(f'Screenshot saved to {filename}')

            return filename
        except KeyboardInterrupt:
            log.info('screenshot stop, Program terminated by user.')
            return ""

    # 根据截图文件路径，删除一张临时截图
    # 是随截随删好，还是统一删除好点？定时删除有点难，运行结束积攒的文件可能爆仓-》循环一次清空一次截图文件夹可以
    def removeTempShot(self, filename):
        # # 删除截图文件
        # if len(filename) == 0:
        #     return
        #
        # if os.path.exists(filename):
        #     os.remove(filename)
        #     # print(f'Screenshot {filename} deleted')
        pass

    # 不截图，仅检测一次，检测失败等待1s
    def checkLocationOnly(self, targetPath, iconName):
        max_loc = []
        bottom_right = []
        target_path = targetPath
        if len(target_path) == 0:
            return (max_loc, bottom_right)

        template_path = IconDirPath + IconHead + iconName + IconTail
        max_loc, bottom_right = self.find_template_in_image(template_path, target_path)
        self.removeTempShot(target_path)
        return (max_loc, bottom_right)

    # 截图一次，检测多次，返回第一次检测到的坐标，但不知道检测到了什么，所有不好用
    def checkLocationsOnce(self, iconNameList):
        max_loc = []
        bottom_right = []
        target_path = self.autoScreemShot()
        if len(target_path) == 0:
            time.sleep(IntervalShot)
            return (max_loc, bottom_right)

        for iconName in iconNameList:
            template_path = IconDirPath + IconHead + iconName + IconTail
            max_loc, bottom_right = self.find_template_in_image(template_path, target_path)
            if len(max_loc) != 0:
                break

        if len(max_loc) == 0:
            time.sleep(IntervalShot)

        self.removeTempShot(target_path)
        return (max_loc, target_path)

    # 截图一次并识别一次按钮，返回顶点坐标, 失败等待intervershot秒
    def checkLocationOnce(self, iconName):
        template_path = IconDirPath + IconHead + iconName + IconTail
        # log.info("开始检测按钮 " + template_path)

        max_loc = []
        bottom_right = []
        target_path = self.autoScreemShot()

        if len(target_path) != 0:
            # log.info("临时截图：" + target_path + ", icon=" + template_path)
            max_loc, bottom_right = self.find_template_in_image(template_path, target_path)
            if len(max_loc) == 0:
                time.sleep(IntervalShot)
        else:
            time.sleep(IntervalShot)

        self.removeTempShot(target_path)
        return (max_loc, bottom_right)

    # 截图并识别至多attemptLimit次，失败等待IntervalShot秒再执行下一次，返回顶点坐标
    def checkLocation(self, iconName, attemptLimit=ATTLIMIT):
        template_path = IconDirPath + IconHead + iconName + IconTail
        # log.info("开始检测按钮 " + template_path)
        num = 0
        max_loc = []
        bottom_right = []
        target_path = ""
        while num < attemptLimit:
            target_path = self.autoScreemShot()

            if len(target_path) == 0:
                num = num + 1
                self.removeTempShot(target_path)
                time.sleep(IntervalShot)
                continue
            else:
                # log.info("临时截图：" + target_path + ", icon=" + template_path)
                max_loc, bottom_right = self.find_template_in_image(template_path, target_path)
                self.removeTempShot(target_path)

            if len(max_loc) == 0:
                num = num + 1
                # log.info("未检测到" + template_path)
                self.removeTempShot(target_path)
                time.sleep(IntervalShot)
                continue
            else:
                self.removeTempShot(target_path)
                return (max_loc, bottom_right)

        self.removeTempShot(target_path)
        return (max_loc, bottom_right)

    # 点击下一步按钮：
    # 识别并获取按钮坐标，点击clickNum次，bDefault=1时不使用按钮坐标而点击默认安全区域，返回bool
    def toNextClick(self, name, bDefault=False, clickNum=1, attmLimit=ATTLIMIT ):
        maxLoc, bottomRight = self.checkLocation(name,attmLimit)
        if len(maxLoc) != 0:
            if bDefault:
                maxLoc = DEFAULT_TOPLOC
                bottomRight = DEFAULT_BOTLOC

            while clickNum > 0:
                self.inputLocationAndClick(maxLoc, bottomRight)
                clickNum = clickNum - 1
            return True
        else:
            # log.info("未找到" + name)
            return False

    # 边缘检测，检测地图下一个点是否是王点
    def boundaryDetection(self, iconName):
        target_path = self.autoScreemShot()
        template_path = IconDirPath + IconHead + iconName + IconTail
        max_loc, bottom_right = self.find_template_in_image(template_path, target_path)
        res = False
        if len(max_loc) == 0:
            # log.info("模板匹配中，在 " + target_path + " 没有检测到边界点 " + template_path)
            pass
        else:
            # log.info("在 " + target_path + " 检测成功")
            if self.compare_images_pixel(template_path, target_path, max_loc, bottom_right):  # top=max, bot = min
                # log.info("像素匹配中，在 " + target_path + " 检测成功 " + template_path)
                res = True
            else:
                # log.info("像素匹配中，在 " + target_path + " 没有检测到边界点 " + template_path)
                pass
        self.removeTempShot(target_path)
        return res

